#include <stdio.h>
// unsigned long long int BASE_DRAM0_ADDR = 0x640000000;
// unsigned long long int BASE_DRAM1_ADDR = 0x660000000;

#define  BASE_AI_ADDR  0x80000000 
unsigned long long int BASE_PT_ADDR = BASE_AI_ADDR;
unsigned long long int BASE_IN_ADDR = BASE_AI_ADDR + 0x400; //0x640000400; 
unsigned long long int BASE_WT_ADDR = BASE_AI_ADDR + 0x010000000; // 0x650000400; 
unsigned long long int BASE_RS_ADDR = BASE_AI_ADDR + 0x020000000; // 0x660000400; 


unsigned int    cfg_cam_valid_num       = 10    ;
unsigned int    cfg_total_pt_num        = 10    ;
unsigned int    cfg_scnn_inchloop       = 3     ;
unsigned int    cfg_start_pt_addr       = 0     ;
unsigned int    cfg_pe_res_shift_num    = 10    ;
unsigned int    cfg_pe_relu_enable      = 0     ;
unsigned int    cfg_cam_search_range[3] = {1,1,1};
unsigned int    cfg_cnn_size[3]         = {3,3,3};
unsigned int    cfg_bias_enable         = 0     ;
unsigned int    cfg_cam_enable          = 0x7   ;//3'b111
unsigned int    cfg_core_enable         = 0xf   ;

unsigned short  bias_core0[] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned short  bias_core1[] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned short  bias_core2[] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned short  bias_core3[] = {0, 0, 0, 0, 0, 0, 0, 0};
int main(void)
{
    printf("[Inst geneortor for SSCONV] \n");
    
    int i;
    unsigned int inst_buffer[1000];
    unsigned int inst127_96;
    unsigned int inst95_64;
    unsigned int inst63_32;
    unsigned int inst31_0;
    int  inst_num = 0;
    // inst for CFG_BIAS0
    inst31_0    = (bias_core0[3]<<8)| (bias_core0[2]<<8) | (bias_core0[1]<<8) | bias_core0[0];
    inst63_32   = (bias_core0[7]<<8)| (bias_core0[6]<<8) | (bias_core0[5]<<8) | bias_core0[4];
    inst95_64   =  0;
    inst127_96  =  0;
    inst_buffer[inst_num] = inst31_0;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst63_32;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst95_64;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst127_96;
    inst_num = inst_num + 1;

    // inst for CFG_BIAS1
    inst31_0    = (bias_core1[3]<<8)| (bias_core1[2]<<8) | (bias_core1[1]<<8) | bias_core1[0];
    inst63_32   = (bias_core1[7]<<8)| (bias_core1[6]<<8) | (bias_core1[5]<<8) | bias_core1[4];
    inst95_64   =  0;
    inst127_96  =  1<<28;
    inst_buffer[inst_num] = inst31_0;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst63_32;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst95_64;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst127_96;
    inst_num = inst_num + 1;

    // inst for CFG_BIAS1
    inst31_0    = (bias_core2[3]<<8)| (bias_core2[2]<<8) | (bias_core2[1]<<8) | bias_core2[0];
    inst63_32   = (bias_core2[7]<<8)| (bias_core2[6]<<8) | (bias_core2[5]<<8) | bias_core2[4];
    inst95_64   =  0;
    inst127_96  =  2<<28;
    inst_buffer[inst_num] = inst31_0;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst63_32;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst95_64;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst127_96;
    inst_num = inst_num + 1;

    // inst for CFG_BIAS1
    inst31_0    = (bias_core3[3]<<8)| (bias_core3[2]<<8) | (bias_core3[1]<<8) | bias_core3[0];
    inst63_32   = (bias_core3[7]<<8)| (bias_core3[6]<<8) | (bias_core3[5]<<8) | bias_core3[4];
    inst95_64   =  0;
    inst127_96  =  3<<28;
    inst_buffer[inst_num] = inst31_0;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst63_32;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst95_64;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst127_96;
    inst_num = inst_num + 1;

    // inst for CFG_PARAM
    inst31_0    =  ((0x3F & cfg_start_pt_addr)<<26) | (cfg_total_pt_num<<11) | cfg_cam_valid_num ;
    inst63_32   =  (cfg_cnn_size[1] << 29)  | (cfg_cnn_size[0] << 26) 
                |  (cfg_cam_search_range[2]<<24) | (cfg_cam_search_range[1]<<22) | (cfg_cam_search_range[0]<<20) 
                |  (cfg_pe_relu_enable<<19) | (cfg_pe_res_shift_num<<11) | (cfg_scnn_inchloop<<9) 
                |  ((0x7FC0) & cfg_start_pt_addr);
    inst95_64   =  (cfg_core_enable<<7) | (cfg_cam_enable<<4) | (cfg_bias_enable <<3) | (cfg_cnn_size[1]);
    inst127_96  =  4<<28;
    inst_buffer[inst_num] = inst31_0;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst63_32;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst95_64;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst127_96;
    inst_num = inst_num + 1;

    // inst for axi2sram pt_sram
    int reverved_transfer_num, transfer_num;
    unsigned long long int  axi_saddr;
    unsigned int sram_saddr;
    axi_saddr = BASE_PT_ADDR;
    sram_saddr = 1<<17;
    reverved_transfer_num = cfg_total_pt_num;
    while (reverved_transfer_num > 0){
        if(reverved_transfer_num > 512){
            transfer_num = 512;
        } else {
            transfer_num = reverved_transfer_num;
        }
        inst31_0 =  (( axi_saddr & 0x1FFFF )<< 15)| transfer_num; //{axi_saddr[16:0] , cfg_total_pt_num[14:0]}
        inst63_32 = ((sram_saddr & 0x1FF)<<23) | (axi_saddr>>17); //{sram_saddr[8:0],axi_saddr[39:17] 23}
        inst95_64 = (1<<11) |  (sram_saddr>>9) ;//{sram_saddr[19:9]}
        inst127_96 = 5<<28;
        inst_buffer[inst_num] = inst31_0;
        inst_num = inst_num + 1;
        inst_buffer[inst_num] = inst63_32;
        inst_num = inst_num + 1;
        inst_buffer[inst_num] = inst95_64;
        inst_num = inst_num + 1;
        inst_buffer[inst_num] = inst127_96;
        inst_num = inst_num + 1;  

        sram_saddr = sram_saddr + 0x200;
        axi_saddr = axi_saddr + 0x1000;
        reverved_transfer_num = reverved_transfer_num - 512;
    }

    // inst for axi2sram in
    axi_saddr =  BASE_IN_ADDR;
    sram_saddr = 4<<17; 
    reverved_transfer_num = (cfg_scnn_inchloop + 1) * cfg_total_pt_num;
    while (reverved_transfer_num > 0){
        if(reverved_transfer_num > 512){
            transfer_num = 512;
        } else {
            transfer_num = reverved_transfer_num;
        }
        inst31_0 =  (( axi_saddr & 0x1FFFF )<< 15)| transfer_num; //{axi_saddr[16:0] , cfg_total_pt_num[14:0]}
        inst63_32 = ((sram_saddr & 0x1FF)<<23) | (axi_saddr>>17); //{sram_saddr[8:0],axi_saddr[39:17] 23}
        inst95_64 = (1<<11) |  (sram_saddr>>9) ;//{sram_saddr[19:9]}
        inst127_96 = 5<<28;
        inst_buffer[inst_num] = inst31_0;
        inst_num = inst_num + 1;
        inst_buffer[inst_num] = inst63_32;
        inst_num = inst_num + 1;
        inst_buffer[inst_num] = inst95_64;
        inst_num = inst_num + 1;
        inst_buffer[inst_num] = inst127_96;
        inst_num = inst_num + 1;  
        reverved_transfer_num = reverved_transfer_num - 512;
        axi_saddr = axi_saddr + 0x1000;
        sram_saddr = sram_saddr + 0x200;
    }

    // inst for axi2sram wt
    axi_saddr = BASE_WT_ADDR;
    sram_saddr = 6<<17;     
    for (i = 0 ; i < 8; i ++ ) {
        inst31_0 =  (( axi_saddr & 0x1FFFF )<< 15)| 512; //{axi_saddr[16:0] , cfg_total_pt_num[14:0]}
        inst63_32 = ((sram_saddr & 0x1FF)<<23) | (axi_saddr>>17); //{sram_saddr[8:0],axi_saddr[39:17] 23}
        inst95_64 = (1<<11) |  (sram_saddr>>9) ;//{sram_saddr[19:9]}
        inst127_96 = 5<<28;
        inst_buffer[inst_num] = inst31_0;
        inst_num = inst_num + 1;
        inst_buffer[inst_num] = inst63_32;
        inst_num = inst_num + 1;
        inst_buffer[inst_num] = inst95_64;
        inst_num = inst_num + 1;
        inst_buffer[inst_num] = inst127_96;
        inst_num = inst_num + 1;  
        axi_saddr = axi_saddr + 0x1000;
        sram_saddr = sram_saddr + 0x200;
    }

    // inst for cnn
    inst31_0 = ((0x3F & cfg_start_pt_addr)<<26) | (cfg_total_pt_num<<11) | cfg_cam_valid_num ;// {cfg_start_pt_addr[5:0], cfg_total_pt_num[14:0], cfg_cam_valid_num[10:0]}
    inst63_32 = cfg_start_pt_addr>>6 ; //cfg_start_pt_addr[14:6]
    inst95_64 = 0;
    inst127_96 = 7<<28;
    inst_buffer[inst_num] = inst31_0;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst63_32;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst95_64;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst127_96;
    inst_num = inst_num + 1;  


    // inst for rs_sram
    
    for (i = 0; i < 4; i++){ // core0 - core 3
        sram_saddr = (5<<17) | (i<<15); 
        axi_saddr = BASE_RS_ADDR + (0x2000 * i);
        reverved_transfer_num = cfg_total_pt_num;
        while (reverved_transfer_num > 0){
            if(reverved_transfer_num > 512){
                transfer_num = 512;
            } else {
                transfer_num = reverved_transfer_num;
            }
            inst31_0 =  (( axi_saddr & 0x1FFFF )<< 15)| transfer_num; //{axi_saddr[16:0] , cfg_total_pt_num[14:0]}
            inst63_32 = ((sram_saddr & 0x1FF)<<23) | (axi_saddr>>17); //{sram_saddr[8:0],axi_saddr[39:17] 23}
            inst95_64 = (0<<11) |  (sram_saddr>>9) ;//{sram_saddr[19:9]}
            inst127_96 = 5<<28;
            inst_buffer[inst_num] = inst31_0;
            inst_num = inst_num + 1;
            inst_buffer[inst_num] = inst63_32;
            inst_num = inst_num + 1;
            inst_buffer[inst_num] = inst95_64;
            inst_num = inst_num + 1;
            inst_buffer[inst_num] = inst127_96;
            inst_num = inst_num + 1;  

            sram_saddr = sram_saddr + 0x200;
            axi_saddr = axi_saddr + 0x1000;
            reverved_transfer_num = reverved_transfer_num - 512;
        }
    }
    
    // inst for finish
    inst31_0 = 0;
    inst63_32 = 0;
    inst95_64 = 0;
    inst127_96 = 9<<28;
    inst_buffer[inst_num] = inst31_0;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst63_32;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst95_64;
    inst_num = inst_num + 1;
    inst_buffer[inst_num] = inst127_96;
    inst_num = inst_num + 1;  

    FILE *fp;
    
    fp=fopen("./instruction_ssconv.h","w");
    fprintf(fp, "int inst[] = {\n");
    for(i = 0; i < inst_num; i++){
        if( i== inst_num - 1)
            fprintf(fp, "0x%08x };\n", inst_buffer[i]);
        else
            fprintf(fp, "0x%08x ,\n", inst_buffer[i]);
    }    
    fclose(fp);

    return 0;
    
}